#include "video_memory.h"
#include "string.h"
#include "video_base.h"


namespace video
{

IMemory::IMemory( int32_t type ):
                              _type(type),
                              _mem(NULL),
                              _size(0),
                              _refs(0),
                              _obs(NULL),
                              _obs_ctx(NULL){


}

IMemory::~IMemory(){

    if( _mem != NULL ){
        delete [] _mem;
        _mem = NULL;
    }
}

bool IMemory::allocate( uint8_t *addr, int32_t size ){

    if( _mem != NULL ){
        return false;
    }

    if( size <= 0 ){
        return false;
    }

    _size = size;
    _mem = (uint8_t*)malloc(size);

    if( _mem == NULL ){
        return false;
    }

    memset( _mem, 0, size );

    return true;
}

bool IMemory::deallocate(){

    if( _mem == NULL ){
        return false;
    }

    free(_mem);
    _mem = NULL;

    return true;
}

int32_t IMemory::set_mgr( IMemoryMgr *mgr, void *ctx ){
    if( mgr == NULL && ctx == NULL ){
        return -1;
    }
    _obs = mgr;
    _obs_ctx = ctx;
    return 0;
}

uint8_t *IMemory::ptr(){
    return _mem;
}
uint32_t IMemory::size() const{
    return _size;
}
int32_t IMemory::type() const{
    return _type;
}

int32_t IMemory::add_ref(){
    _refs++;
}
int32_t IMemory::release(){

    --_refs;

    if( _refs > 0 )
        return 0;


    if( !_obs ){
        delete this;
    } else {
        _obs->signal_mem_release( this, _obs_ctx );
    }

    return 0;
}

Video_Frame::Video_Frame( int32_t type, int32_t ts, int32_t w, int32_t h, int32_t w_stride, int32_t h_stride ):
                        _timestamp(ts),
                        _w(w),
                        _h(h),
                        _w_stride(w_stride),
                        _h_stride(h_stride),
                        _type(type),
                        IMemory(type) {
}

bool Video_Frame::allocate( uint8_t *addr, int32_t size ){

    int32_t act_size = caclu_size(_type);
    return IMemory::allocate( NULL, act_size );
}

bool Video_Frame::deallocate(){
    return IMemory::deallocate();
}


int32_t Video_Frame::set_timestamp( int32_t ts ){
    return (_timestamp = ts);
}

int32_t Video_Frame::timestamp() const{
    return _timestamp;
}


uint8_t *Video_Frame::memory(){
    return ptr();
}


int32_t Video_Frame::caclu_size( int32_t type ){
    int32_t size = -1;
    switch (type)
    {
    case VID_FRAME_TYPE_I410:
    case VID_FRAME_TYPE_NV21:
    case VID_FRAME_TYPE_NV12:
        size = ((_w_stride*_h_stride)*3/2);
        break;

    default:
        break;
    }
    return size;
}



Buffer_Frame::Buffer_Frame( int32_t type, int32_t ts, int32_t size ):
                                                        _type(type),
                                                        _timestamp(ts),
                                                        _size(size),
                                                        IMemory(type){

}

bool Buffer_Frame::allocate( uint8_t *addr, int32_t size ){

    return IMemory::allocate( NULL, _size );
}


bool Buffer_Frame::deallocate(){
    return IMemory::deallocate();
}


int32_t Buffer_Frame::set_timestamp( int32_t ts ){
    return (_timestamp = ts);
}


int32_t Buffer_Frame::timestamp() const{
    return _timestamp;
}

uint8_t *Buffer_Frame::memory(){
    return ptr();
}



}